#include "pch.h"

#include "math/directx/dxquaternion.h"
#include "core/config.h"


#ifdef RE_USE_DX


namespace Math
{

	quaternion::quaternion():
m_vec(XMQuaternionIdentity())
{

}

quaternion::quaternion( scalar x, scalar y, scalar z, scalar w )
{
	this->m_vec = XMVectorSet(x, y, z, w);
}

quaternion::quaternion( const float4& rhs )
{
	this->m_vec = rhs.m_vec;
}

quaternion::quaternion( XMVECTOR rhs )
{
	this->m_vec = rhs;
}

void quaternion::operator =( const float4& rhs )
{
	this->m_vec = rhs.m_vec;
}

void quaternion::operator =( XMVECTOR rhs )
{
	this->m_vec = rhs;
}

bool quaternion::operator ==( const float4& rhs ) const
{
	return (0 != XMVector4Equal(this->m_vec, rhs.m_vec));
}

bool quaternion::operator !=( const float4& rhs ) const
{
	return (0 != XMVector4NotEqual(this->m_vec, rhs.m_vec));
}

void quaternion::set( scalar x, scalar y, scalar z, scalar w )
{
	this->m_vec = XMVectorSet(x, y, z, w);
}

void quaternion::set( const float4& f )
{
	this->m_vec = f.m_vec;
}

void quaternion::setx( scalar x )
{
	this->m_vec = XMVectorSetXPtr(this->m_vec, &x);
}

void quaternion::sety( scalar y )
{
	this->m_vec = XMVectorSetYPtr(this->m_vec, &y);
}

void quaternion::setz( scalar z )
{
	this->m_vec = XMVectorSetZPtr(this->m_vec, &z);
}

void quaternion::setw( scalar w )
{
	this->m_vec = XMVectorSetWPtr(this->m_vec, &w);
}

scalar& quaternion::getx()
{
	return this->m_vec.m128_f32[0];
}

scalar& quaternion::gety()
{
	return this->m_vec.m128_f32[1];
}

scalar& quaternion::getz()
{
	return this->m_vec.m128_f32[2];
}

scalar& quaternion::getw()
{
	return this->m_vec.m128_f32[3];
}

scalar quaternion::getx() const
{
	return float4::unwrapx(this->m_vec);
}

scalar quaternion::gety() const
{
	return float4::unwrapy(this->m_vec);
}

scalar quaternion::getz() const
{
	return float4::unwrapz(this->m_vec);
}

scalar quaternion::getw() const
{
	return float4::unwrapw(this->m_vec);
}

bool quaternion::isidentity() const
{
	return (0 != XMQuaternionIsIdentity(this->m_vec));
}

scalar quaternion::length() const
{
	return float4::unwrapw(XMQuaternionLength(this->m_vec));
}

scalar quaternion::lengthsq() const
{
	return float4::unwrapw(XMQuaternionLengthSq(this->m_vec));
}

quaternion quaternion::barycentric( const quaternion& q0, const quaternion& q1, const quaternion& q2, scalar f, scalar g )
{
	return XMQuaternionBaryCentric(q0.m_vec, q1.m_vec, q2.m_vec, f, g);
}

quaternion quaternion::conjugate( const quaternion& q )
{
	return XMQuaternionConjugate(q.m_vec);
}

scalar quaternion::dot( const quaternion& q1, const quaternion& q2 )
{
	return float4::unwrapw(XMQuaternionDot(q1.m_vec, q2.m_vec));
}

quaternion quaternion::exp( const quaternion& q )
{
	return XMQuaternionExp(q.m_vec);
}

quaternion quaternion::identity()
{
	return XMQuaternionIdentity();
}

quaternion quaternion::inverse( const quaternion& q )
{
	return XMQuaternionInverse(q.m_vec);
}

quaternion quaternion::ln( const quaternion& q )
{
	return XMQuaternionLn(q.m_vec);
}

quaternion quaternion::multiply( const quaternion& q1, const quaternion& q2 )
{
	return XMQuaternionMultiply(q1.m_vec, q2.m_vec);
}

quaternion quaternion::normalize( const quaternion& q )
{
	return XMQuaternionNormalize(q.m_vec);
}

quaternion quaternion::rotationaxis( const float4& axis, scalar angle )
{
	return XMQuaternionRotationAxis(axis.m_vec, angle);
}

quaternion quaternion::rotationmatrix( const matrix& m )
{
	return XMQuaternionRotationMatrix(m.m_matrix);
}

quaternion quaternion::rotateionyawpitchroll( scalar yaw, scalar pitch, scalar roll )
{
	return XMQuaternionRotationRollPitchYaw(pitch, yaw, roll);
}

quaternion quaternion::slerp( const quaternion& q1, const quaternion& q2, scalar s )
{
	return XMQuaternionSlerp(q1.m_vec, q2.m_vec, s);
}

void quaternion::squadsetup( const quaternion& q1, const quaternion& q2, const quaternion& q3, const quaternion& q4, quaternion& outA, quaternion& outB, quaternion& outC )
{
	XMQuaternionSquadSetup(&outA.m_vec, &outB.m_vec, &outC.m_vec, q1.m_vec, q2.m_vec, q3.m_vec, q4.m_vec);
}

quaternion quaternion::squad( const quaternion& q1, const quaternion& q2, const quaternion& b, const quaternion& c, scalar s )
{
	return XMQuaternionSquad(q1.m_vec, q2.m_vec, b.m_vec, c.m_vec, s);
}

void quaternion::toaxisangle( const quaternion& q, float4& outAxis, scalar& outAngle )
{
	return XMQuaternionToAxisAngle(&outAxis.m_vec, &outAngle, q.m_vec);
}

}

#endif // RE_USE_DX